package rs.edu.fit.setupdata;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

import rs.edu.fit.model.Exam;
import rs.edu.fit.model.ExamSchedule;
import rs.edu.fit.model.Student;

public class FillExams {
	private List<Student> lStudents;
	private List<Exam> lExams;
	private List<ExamSchedule> lExamsSchedule;
	
	private Random r = new Random();
	private Logger log = Logger.getLogger("rs.edu.fit.setupdata.FillExams");
	
	private final static int NUM_EXAMS_ENROLLED = 3;
	private final static int DIFF = 1;

	@SuppressWarnings("unused")
	private FillExams() {
		
	}

	public FillExams(List<Student> lStudents, List<Exam> lExams) {
		this.lStudents = lStudents;
		this.lExams = lExams;
		lExamsSchedule = new ArrayList<ExamSchedule>();
		
		BasicConfigurator.configure();
	}
	
	public void execute() {
		wrapExamsIntoExamsSchedule();
		Collections.sort(lStudents, studentComparator());
		Collections.sort(lExamsSchedule, examScheduleComparator());
		for (int i=0, n=lStudents.size(); i<n; i++) {
			Student std = lStudents.get(i);
//			log.info(std.toString());
			for (int j=0; j<NUM_EXAMS_ENROLLED; j++) {
				if (isStudentOnFirstYear(std)) {
					ExamSchedule examScheduleTmp = lExamsSchedule.get(r.nextInt(lExamsSchedule.size()/3 + DIFF));
					std.addExam(examScheduleTmp.getExam());
					examScheduleTmp.addStudent(std);
//					log.info("Student of first year");
				} else if (isStudentOnSecondYear(std)) {
					ExamSchedule examScheduleTmp = lExamsSchedule.get(r.nextInt(2 * lExamsSchedule.size()/3 + DIFF));
					std.addExam(examScheduleTmp.getExam());
					examScheduleTmp.addStudent(std);
//					log.info("Student of second year");					
				} else if (isStudentOnThirdYear(std)) {
					int examScheduleNumber = r.nextInt(2 * lExamsSchedule.size()/3 + DIFF) + new Integer(lExamsSchedule.size()/3);
					ExamSchedule examScheduleTemp = lExamsSchedule.get(examScheduleNumber);
					std.addExam(examScheduleTemp.getExam());
					examScheduleTemp.addStudent(std);
//					log.info("Student of third year");
				} else {
					log.warn("Student did not get assign exam");
				}
			}
		}
		
	}
	
	public Comparator<Student> studentComparator() {
		return new Comparator<Student>() {

			@Override
			public int compare(Student s1, Student s2) {
				
				return s1.getYearOfStudy() - s2.getYearOfStudy();
			}
		};
	}
	
	public Comparator<ExamSchedule> examScheduleComparator() {
		return new Comparator<ExamSchedule>() {

			@Override
			public int compare(ExamSchedule e1, ExamSchedule e2) {
				
				return e1.getExam().getYearOfStudy() - e2.getExam().getYearOfStudy();
			}
			
		};
	}
	
	private boolean isStudentOnFirstYear(final Student std) {
		return std.getYearOfStudy() == 1;
	}
	
	private boolean isStudentOnSecondYear(final Student std) {
		return std.getYearOfStudy() == 2;
	}
	
	private boolean isStudentOnThirdYear(final Student std) {
		return std.getYearOfStudy() == 3;
	}
	
	private void wrapExamsIntoExamsSchedule() {
		for (Exam exam : lExams) {
			lExamsSchedule.add( new ExamSchedule(exam));
		}
	}
	
	/* Only getter and setters, no logic here. */

	public final List<Student> getlStudents() {
		return lStudents;
	}

	public final void setlStudents(List<Student> lStudents) {
		this.lStudents = lStudents;
	}

	public final List<Exam> getlExams() {
		return lExams;
	}

	public final void setlExams(List<Exam> lExams) {
		this.lExams = lExams;
	}

	public final List<ExamSchedule> getlExamsSchedule() {
		return lExamsSchedule;
	}

	public final void setlExamsSchedule(List<ExamSchedule> lExamsSchedule) {
		this.lExamsSchedule = lExamsSchedule;
	}
}
